package com.FQJ.stock.service.impl;

import com.FQJ.stock.mapper.*;
import com.FQJ.stock.pojo.domain.*;
import com.FQJ.stock.pojo.vo.StockInfoConfig;
import com.FQJ.stock.service.StockService;
import com.FQJ.stock.utils.DateTimeUtil;
import com.FQJ.stock.vo.resp.PageResult;
import com.FQJ.stock.vo.resp.R;
import com.FQJ.stock.vo.resp.ResponseCode;
import com.alibaba.excel.EasyExcel;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Service("stockService")
@Slf4j
public class StockServiceImpl implements StockService {

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockInfoConfig stockInfoConfig;

	/**
	 * 注入本地缓存bean
	 */
	@Autowired
	private Cache<String,Object> caffeineCache;
    /**
     * 获取国内大盘的实时数据
     * @return
     */
    @Override
    public R<List<InnerMarketDomain>> innerIndexAll() {
		//从缓存中加载数据，如果不存在，则走补偿策略获取数据，并存入本地缓存
		R<List<InnerMarketDomain>> data=(R<List<InnerMarketDomain>>) caffeineCache.get("innerMarketKey",key->{
			//1.获取国内A股大盘的id集合
			List<String> inners = stockInfoConfig.getInner();
			//2.获取最近股票交易日期
			Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
			//TODO mock测试数据，后期数据通过第三方接口动态获取实时数据 可删除
			lastDate=DateTime.parse("2022-01-02 09:32:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
			//3.将获取的java Date传入接口
			List<InnerMarketDomain> list= stockMarketIndexInfoMapper.getMarketInfo(inners,lastDate);
			//4.返回查询结果
			return R.ok(list);
		});
		return data;
    }

	@Autowired
	private StockBlockRtInfoMapper stockBlockRtInfoMapper;
	/**
	 *需求说明: 沪深两市板块分时行情数据查询，以交易时间和交易总金额降序查询，取前10条数据
	 * @return
	 */
	@Override
	public R<List<StockBlockDomain>> sectorAllLimit() {

		//获取股票最新交易时间点
		Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
		//TODO mock数据,后续删除
		lastDate=DateTime.parse("2021-12-21 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
		//1.调用mapper接口获取数据
		List<StockBlockDomain> infos=stockBlockRtInfoMapper.sectorAllLimit(lastDate);
		//2.组装数据
		if (CollectionUtils.isEmpty(infos)) {
			return R.error(ResponseCode.NO_RESPONSE_DATA.getMessage());
		}
		return R.ok(infos);
	}

	@Autowired
	private StockOuterMarketIndexInfoMapper stockOuterMarketIndexInfoMapper;
	@Override
	public R<List<OuterMarketDomain>> externalIndex() {
		//获取股票最新交易时间点
		Date lastDate=DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
		//TODO mock数据,后续删除
		lastDate=DateTime.parse("2022-05-18 15:58:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
		//1.调用mapper接口获取数据
		List<OuterMarketDomain> infos=stockOuterMarketIndexInfoMapper.externalIndex(lastDate);
		//4.返回查询结果
		return R.ok(infos);
	}

	@Autowired
	private StockRtInfoMapper stockRtInfoMapper;
	@Override
	public R<PageResult> pageResultR(Integer page, Integer pageSize) {
		//获取股票最新交易时间点
		Date lastDate=DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
		//TODO mock数据,后续删除
		lastDate=DateTime.parse("2021-12-30 09:42:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

		PageHelper.startPage(page,pageSize);
		List<StockUpdownDomain> list=stockRtInfoMapper.findAll(lastDate);
		PageResult<StockUpdownDomain> result=new PageResult<>(new PageInfo<>(list));
		return R.ok(result);
	}
	//导出excel表
	@Override
	public void pageResultR1(Integer page, Integer pageSize, HttpServletResponse response) {
		// //获取股票最新交易时间点
		// Date lastDate=DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
		// //TODO mock数据,后续删除
		// lastDate=DateTime.parse("2021-12-30 09:42:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
		//
		// PageHelper.startPage(page,pageSize);
		// List<StockUpdownDomain> list=stockRtInfoMapper.findAll(lastDate);
		// PageInfo<StockUpdownDomain> pageInfo = new PageInfo<>(list);
		//
		// /**
		//  * excel难点部分
		//  */
		// EasyExcel.write("D:\\test.xls",StockUpdownDomain.class).sheet(pageInfo.getPageNum()).doWrite(pageInfo.getList());
		//
		// return R.ok();
		//1.获取分页数据
		Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
		//TODO 伪造数据，后续删除
		lastDate=DateTime.parse("2022-07-07 14:43:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
		PageHelper.startPage(page,pageSize);
		List<StockUpdownDomain> infos=stockRtInfoMapper.findAll(lastDate);
		response.setCharacterEncoding("utf-8");
		try {
			//2.判断分页数据是否为空，为空则响应json格式的提示信息
			if (CollectionUtils.isEmpty(infos)) {
				R<Object> error = R.error(ResponseCode.NO_RESPONSE_DATA);
				//将error转化成json格式字符串
				String jsonData = new ObjectMapper().writeValueAsString(error);
				//设置响应的数据格式 告知浏览器传入的数据格式
				response.setContentType("application/json");
				//设置编码格式
				//            response.setCharacterEncoding("utf-8");
				//响应数据
				response.getWriter().write(jsonData);
				return;
			}
			//3.调动EasyExcel数据导出
			// 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
			response.setContentType("application/vnd.ms-excel");
//        response.setCharacterEncoding("utf-8");
			// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
			String fileName = URLEncoder.encode("股票涨幅数据表格", "UTF-8");
			//指定excel导出时默认的文件名称，说白了就是告诉浏览器下载文件时默认的名称为：股票涨幅数据表格
			response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
			EasyExcel.write(response.getOutputStream(), StockUpdownDomain.class).sheet("股票涨幅信息").doWrite(infos);
		} catch (Exception e) {
			log.error("导出时间：{},当初页码：{}，导出数据量：{}，发生异常信息：{}",lastDate,page,pageSize,e.getMessage());
		}

	}

	/**
	 * 统计大盘T日统计/T-1统计每分钟交易量对比
	 * @return
	 */
	@Override//时间是有点不对的
	public R<Map<String, List<Map>>> getCompareStockTradeAmt() {
		//1.获取T日
		DateTime lastDate4Stock = DateTimeUtil.getLastDate4Stock(DateTime.now());
		//mock数据
		lastDate4Stock=DateTime.parse("2021-12-28 14:55:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
		Date tEndDate = lastDate4Stock.toDate();
		//获取开盘时间
		Date tStartDate = DateTimeUtil.getOpenDate(lastDate4Stock).toDate();

		//2.获取T-1日
		DateTime preTEndDateTime = DateTimeUtil.getPreviousTradingDay(lastDate4Stock);
		Date preTEndDate = preTEndDateTime.toDate();
		Date tPreStartDate = DateTimeUtil.getOpenDate(preTEndDateTime).toDate();
		stockInfoConfig.getInner();
		//3.获取mapper
		List<Map> TSumAmt = stockMarketIndexInfoMapper.getSumAmtInfo(tStartDate, tEndDate,stockInfoConfig.getInner());
		List<Map> PreSumAmt = stockMarketIndexInfoMapper.getSumAmtInfo(tPreStartDate, preTEndDate,stockInfoConfig.getInner());
		Map<String, List<Map>> map = new HashMap<>();
		map.put("amtList",TSumAmt);
		map.put("yesAmtList",PreSumAmt);
		return R.ok(map);
	}

	@Override
	public R<Map<String, Object>> stockUpDownScopeCount() {
		//1.获取股票最新一次交易的时间点
		DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());

		//mock data
		curDateTime=DateTime.parse("2022-01-06 09:55:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
		Date curDate=curDateTime.toDate();

		Map<String, Object> map = new HashMap<>();
		map.put("time",curDateTime.toString("yyyy-MM-dd HH:mm:ss"));

		List<Map> list=stockRtInfoMapper.getStockCount(curDate);

		List<String> upDownRange = stockInfoConfig.getUpDownRange();
		/**
		 * 下面是普通方法，之后我写一个stream流
		 */
		// List<Map> list1=new ArrayList<>();
		// for(String title:upDownRange){
		// 	Map map2=null;
		// 	for(Map map1:list){
		// 		if (map1.containsValue(title)){
		// 			map2=map1;
		// 			break;
		// 		}
		// 	}
		// 	if (map2==null){
		// 		map2 = new HashMap<>();
		// 		map2.put("count",0);
		// 		map2.put("title",title);
		// 	}
		// 	list1.add(map2);
		// }

		//下面失败了
		// List<Map> list1 = list.stream().map((item) -> {//这样只能获得五个数据
		// 	System.out.println("item"+item);
		// 	Map  map1 = new HashMap<>();
		// 	for (String title : upDownRange) {
		// 		if (item.containsValue(title)) {
		// 			map1=item;
		// 			break;
		// 		}else {
		// 			map1.put("count",0);//这样只能会覆盖
		// 			map1.put("title",title);//这样会覆盖
		// 		}
		// 	}
		// 	System.out.println("map1"+map1);
		// 	return map1;
		// }).collect(Collectors.toList());

		//ok了
		List<Map> list1 = upDownRange.stream().map(item -> {
			Map map1=null;
			for (Map map2:list){
				if (map2.containsValue(item)){
					map1=map2;
					break;
				}
			}
			if (map1==null){
				map1=new HashMap<String,Object>();
				map1.put("count",0);
				map1.put("title",item);
			}
			return map1;
		}).collect(Collectors.toList());

		map.put("infos",list1);

		return R.ok(map);
	}

	/**
	 * 获得分时的数据
	 * @param code
	 * @return
	 */
	@Override
	public R<List<Stock4MinuteDomain>> stockScreenTimeSharing(String code) {
		//1.获取最近最新的交易时间点和对应的开盘日期
		//1.1 获取最近有效时间点
		DateTime lastDate4Stock = DateTimeUtil.getLastDate4Stock(DateTime.now());
		Date endTime = lastDate4Stock.toDate();
		//TODO mockdata
		endTime=DateTime.parse("2021-12-30 14:47:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

		//1.2 获取最近有效时间点对应的开盘日期
		DateTime openDateTime = DateTimeUtil.getOpenDate(lastDate4Stock);
		Date startTime = openDateTime.toDate();
		//TODO MOCK DATA
		startTime=DateTime.parse("2021-12-30 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
		//2.根据股票code和日期范围查询
		List<Stock4MinuteDomain> list=stockRtInfoMapper.getStockInfoByCodeAndDate(code,startTime,endTime);
		//判断非空处理
		if (CollectionUtils.isEmpty(list)) {
			list=new ArrayList<>();
		}
		//3.返回响应数据
		return R.ok(list);
	}

	/**
	 * 功能描述：单个个股日K数据查询 ，可以根据时间区间查询数日的K线数据
	 * 		默认查询历史20天的数据；
	 * @param code 股票编码
	 * @return
	 */
	@Override
	public R<List<Stock4EvrDayDomain>> stockCreenDkLine(String code) {
		//1.获取查询的日期范围
		//1.1 获取截止时间
		DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
		Date endTime = endDateTime.toDate();
		//TODO MOCKDATA
		endTime=DateTime.parse("2022-06-02 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
		//1.2 获取开始时间
		DateTime startDateTime = endDateTime.minusDays(10);
		Date startTime = startDateTime.toDate();
		//TODO MOCKDATA
		startTime=DateTime.parse("2022-01-01 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
		//2.调用mapper接口获取查询的集合信息-方案1
		List<Stock4EvrDayDomain> data= stockRtInfoMapper.getStockInfo4EvrDay(code,startTime,endTime);
		//3.组装数据，响应
		return R.ok(data);
	}

	@Override
	public R<List<StockUpdownDomain>> stockIncrease() {
		//获取股票最新交易时间点
		Date lastDate=DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
		//TODO mock数据,后续删除
		lastDate=DateTime.parse("2022-07-07 14:55:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
		//2.调用mapper接口查询
		List<StockUpdownDomain>infos=stockRtInfoMapper.findAll(lastDate);
		if(CollectionUtils.isEmpty(infos)){
			return R.error(ResponseCode.NO_RESPONSE_DATA);
		}
		return R.ok(infos);
	}

	/**
	 * 统计最新交易日下股票每分钟涨跌停的数量
	 * @return
	 */
	@Override
	public R<Map> getStockUpdownCount() {
		//1.获取最新的交易时间范围 openTime  curTime
		//1.1 获取最新股票交易时间点
		DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
		Date curTime = curDateTime.toDate();
		//TODO
		curTime= DateTime.parse("2022-01-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
		//1.2 获取最新交易时间对应的开盘时间
		DateTime openDate = DateTimeUtil.getOpenDate(curDateTime);
		Date openTime = openDate.toDate();
		//TODO
		openTime= DateTime.parse("2022-01-06 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
		//2.查询涨停数据
		//约定mapper中flag入参： 1-》涨停数据 0：跌停
		List<Map> upCounts=stockRtInfoMapper.getStockUpdownCount(openTime,curTime,1);
		//3.查询跌停数据
		List<Map> dwCounts=stockRtInfoMapper.getStockUpdownCount(openTime,curTime,0);
		//4.组装数据
		HashMap<String, List> mapInfo = new HashMap<>();
		mapInfo.put("upList",upCounts);
		mapInfo.put("downList",dwCounts);
		//5.返回结果
		return R.ok(mapInfo);
	}
}
